package org.yan.stock.server.c2dm;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

/**
 * Stores config information related to data messaging.
 * 
 */
class C2DMConfigLoader {
    private final PersistenceManagerFactory PMF;
    private static final Logger log = Logger.getLogger(C2DMConfigLoader.class.getName());

    String currentToken;
    String c2dmUrl;
    
    C2DMConfigLoader(PersistenceManagerFactory pmf) {
        this.PMF = pmf;
    }

    /**
     * Update the token. 
     * 
     * Called on "Update-Client-Auth" or when admins set a new token.
     * @param token
     */
    public void updateToken(String token) {
        if (token != null) {
            currentToken = token;
            PersistenceManager pm = PMF.getPersistenceManager();
            try {
                C2DMConfig conf = getDataMessagingConfig(pm);
                conf.setAuthToken(token);
                pm.makePersistent(conf);
            } finally {
                pm.close();
            }
        }
    }
    
    /** 
     * Token expired
     */
    public void refreshCachedToken() {
    	InputStream is = null;
    	OutputStream out = null;
    	String newToken = null;
    	try {
            is = C2DMConfigLoader.class.getClassLoader().getResourceAsStream("auth.properties");
            if (is != null) {
                Properties prop = new Properties();
                prop.load(is);
                
                StringBuilder postDataBuilder = new StringBuilder();
                postDataBuilder.append("accountType=").append(prop.get("accountType"));
                postDataBuilder.append("&Email=").append(prop.get("Email"));
                postDataBuilder.append("&Passwd=").append(prop.get("Passwd"));
                postDataBuilder.append("&service=").append(prop.get("service"));
                postDataBuilder.append("&source=").append(prop.get("source"));
                byte[] postData = postDataBuilder.toString().getBytes("UTF-8");
                
                URL url = new URL(prop.getProperty("url"));
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setDoOutput(true);
                conn.setUseCaches(false);
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");

                out = conn.getOutputStream();
                out.write(postData);
                
                BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line = null;
                while((line=reader.readLine()) != null) {
                	if(line.startsWith("Auth=")) {
                		newToken = line.replace("Auth=", "");
                		updateToken(newToken);
                	}
                }
            }
        } catch (Throwable t) {
            log.log(Level.SEVERE, "Can't refresh token, use admin console", t);
        }
        finally {
        	try {
        		out.close();
				is.close();
			} catch (IOException e) {
				log.log(Level.SEVERE, "Can't close io", e);
			}
        }
    }

    /**
     * Return the auth token from the database. Should be called 
     * only if the old token expired.
     *
     * @return
     */
    public String getToken() {
        if (currentToken == null) {
            currentToken = getDataMessagingConfig().getAuthToken();
        } 
        return currentToken;
    }
    
    public String getC2DMUrl() {
        if (c2dmUrl == null) {
            c2dmUrl = getDataMessagingConfig().getC2DMUrl();
        }
        return c2dmUrl;
    }
    
    public C2DMConfig getDataMessagingConfig() {
        PersistenceManager pm = PMF.getPersistenceManager();
        try {
            C2DMConfig dynamicConfig = getDataMessagingConfig(pm);
            return dynamicConfig;
        } finally {
            pm.close();
        }
    }

    private C2DMConfig getDataMessagingConfig(PersistenceManager pm) {
        Key key = KeyFactory.createKey(C2DMConfig.class.getSimpleName(), 1);
        C2DMConfig dmConfig = null;
        InputStream is = null;
        BufferedReader reader = null;
        try {
            dmConfig = pm.getObjectById(C2DMConfig.class, key);
        } catch (JDOObjectNotFoundException e) {
            // Create a new JDO object
            dmConfig = new C2DMConfig();
            dmConfig.setKey(key);
            // Must be in classpath, before sending. Do not checkin !
            try {
                is = this.getClass().getClassLoader().getResourceAsStream("dataMessagingToken.txt");
                if (is != null) {
                    reader = new BufferedReader(new InputStreamReader(is));
                    String token = reader.readLine();
                    dmConfig.setAuthToken(token);
                }
            } catch (Throwable t) {
                log.log(Level.SEVERE, "Can't load initial token, use admin console", t);
            }
            finally {
            	try {
					is.close();
					reader.close();
				} catch (IOException e1) {
					log.log(Level.SEVERE, "Can't close InputSteam", e1);
				}
            }
            pm.makePersistent(dmConfig);
        }
        return dmConfig;
    }
    
}
